package top.xuziyi.crawler.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import top.xuziyi.common.pojo.*;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class StockUtils {

    private static Logger logger = LogManager.getLogger(StockUtils.class.getName());

    public static ObjectMapper MAPPER = new ObjectMapper();

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    public static StockDayNormal getStockDayNormal(JsonNode jsonNode) {
        ArrayNode array = checkJsonNode(jsonNode);
        if (array == null) {
            return null;
        }

        StockDayNormal stock = new StockDayNormal();
        try {
            //"timestamp","volume","open","high","low","close","chg","percent","turnoverrate"
            //[1439395200000,74034209,15.47,15.56,15.29,15.45,0.06,0.39,0.5]

            //System.out.println(array.get(0).asText());//日期 timestamp
            Date date = new Date(Long.parseLong(array.get(0).asText()));
            stock.setDate(sdf.parse(sdf.format(date)));

            //System.out.println(array.get(1));//交易量 volume
            stock.setVolume(Long.parseLong(array.get(1).asText()));

            //System.out.println(array.get(2).asText());//开盘价 open

            stock.setOpen(string2int(array.get(2).asText()));

            //System.out.println(array.get(3).asText());//最高价 high
            stock.setHigh(string2int(array.get(3).asText()));

            //System.out.println(array.get(4).asText());//最低价 low
            stock.setLow(string2int(array.get(4).asText()));

            //System.out.println(array.get(5).asText());//收盘价 close
            stock.setClose(string2int(array.get(5).asText()));

            //System.out.println(array.get(8).asText());//换手率 turnoverrate
            stock.setTurnoverrate(string2int(array.get(8).asText()));

            //状态初始值为0
            stock.setStatus("0");

            return stock;
        } catch (Exception e) {
            System.out.println("--------解析股票数据有异常----------");
            for (int i = 0; i < array.size(); i++) {
                System.out.println(array.get(i).asText());
            }
            throw new RuntimeException("解析股票数据有异常,数据为:");
        }
    }


    public static StockDayAfter getStockDayAfter(JsonNode jsonNode) {
        ArrayNode array = checkJsonNode(jsonNode);
        if (array == null) {
            return null;
        }

        StockDayAfter stock = new StockDayAfter();

        try {
            //"timestamp","volume","open","high","low","close","chg","percent","turnoverrate"
            //[1439395200000,74034209,15.47,15.56,15.29,15.45,0.06,0.39,0.5]

            //System.out.println(array.get(0).asText());//日期 timestamp
            Date date = new Date(Long.parseLong(array.get(0).asText()));
            stock.setDate(sdf.parse(sdf.format(date)));

            //System.out.println(array.get(1));//交易量 volume
            stock.setVolume(Long.parseLong(array.get(1).asText()));

            //System.out.println(array.get(2).asText());//开盘价 open

            stock.setOpen(string2int(array.get(2).asText()));

            //System.out.println(array.get(3).asText());//最高价 high
            stock.setHigh(string2int(array.get(3).asText()));

            //System.out.println(array.get(4).asText());//最低价 low
            stock.setLow(string2int(array.get(4).asText()));

            //System.out.println(array.get(5).asText());//收盘价 close
            stock.setClose(string2int(array.get(5).asText()));

            //System.out.println(array.get(8).asText());//换手率 turnoverrate
            stock.setTurnoverrate(string2int(array.get(8).asText()));

            //状态初始值为0
            stock.setStatus("0");

            return stock;
        } catch (Exception e) {
            System.out.println("--------解析股票数据有异常----------");
            for (int i = 0; i < array.size(); i++) {
                System.out.println(array.get(i).asText());
            }
            throw new RuntimeException("解析股票数据有异常,数据为:");
        }
    }

    public static StockWeek getStockWeek(JsonNode jsonNode) {
        ArrayNode array = checkJsonNode(jsonNode);
        if (array == null) {
            return null;
        }

        StockWeek stock = new StockWeek();

        try {
            //"timestamp","volume","open","high","low","close","chg","percent","turnoverrate"
            //[1439395200000,74034209,15.47,15.56,15.29,15.45,0.06,0.39,0.5]

            //System.out.println(array.get(0).asText());//日期 timestamp
            Date date = new Date(Long.parseLong(array.get(0).asText()));
            stock.setDate(sdf.parse(sdf.format(date)));

            //System.out.println(array.get(1));//交易量 volume
            stock.setVolume(Long.parseLong(array.get(1).asText()));

            //System.out.println(array.get(2).asText());//开盘价 open

            stock.setOpen(string2int(array.get(2).asText()));

            //System.out.println(array.get(3).asText());//最高价 high
            stock.setHigh(string2int(array.get(3).asText()));

            //System.out.println(array.get(4).asText());//最低价 low
            stock.setLow(string2int(array.get(4).asText()));

            //System.out.println(array.get(5).asText());//收盘价 close
            stock.setClose(string2int(array.get(5).asText()));

            //System.out.println(array.get(8).asText());//换手率 turnoverrate
            stock.setTurnoverrate(string2int(array.get(8).asText()));

            //状态初始值为0
            stock.setStatus("0");

            return stock;
        } catch (Exception e) {
            System.out.println("--------解析股票数据有异常----------");
            for (int i = 0; i < array.size(); i++) {
                System.out.println(array.get(i).asText());
            }
            throw new RuntimeException("解析股票数据有异常,数据为:");
        }
    }


    public static StockMonth getStockMonth(JsonNode jsonNode) {
        ArrayNode array = checkJsonNode(jsonNode);
        if (array == null) {
            return null;
        }

        StockMonth stock = new StockMonth();
        try {
            //"timestamp","volume","open","high","low","close","chg","percent","turnoverrate"
            //[1439395200000,74034209,15.47,15.56,15.29,15.45,0.06,0.39,0.5]

            //System.out.println(array.get(0).asText());//日期 timestamp
            Date date = new Date(Long.parseLong(array.get(0).asText()));
            stock.setDate(sdf.parse(sdf.format(date)));

            //System.out.println(array.get(1));//交易量 volume
            stock.setVolume(Long.parseLong(array.get(1).asText()));

            //System.out.println(array.get(2).asText());//开盘价 open

            stock.setOpen(string2int(array.get(2).asText()));

            //System.out.println(array.get(3).asText());//最高价 high
            stock.setHigh(string2int(array.get(3).asText()));

            //System.out.println(array.get(4).asText());//最低价 low
            stock.setLow(string2int(array.get(4).asText()));

            //System.out.println(array.get(5).asText());//收盘价 close
            stock.setClose(string2int(array.get(5).asText()));

            //System.out.println(array.get(8).asText());//换手率 turnoverrate
            stock.setTurnoverrate(string2int(array.get(8).asText()));

            //状态初始值为0
            stock.setStatus("0");

            return stock;
        } catch (Exception e) {
            System.out.println("--------解析股票数据有异常----------");
            for (int i = 0; i < array.size(); i++) {
                System.out.println(array.get(i).asText());
            }
            throw new RuntimeException("解析股票数据有异常,数据为:");
        }
    }

    /**
     * 检查数据是否合法
     */
    private static ArrayNode checkJsonNode(JsonNode jsonNode) {
        ArrayNode array = (ArrayNode) jsonNode;
        if (jsonNode == null) {
            logger.error("解析的数据为空");
            return null;
        }
        if (array.size() == 0) {
            logger.error("解析的数据没有值");
            return null;
        }
        return array;
    }

    private static int string2int(String str) {
        if (str == null || "".equals(str) || "null".equals(str)) {
            return 0;
        }

        float p = Float.parseFloat(str);
        //Math.round(x)中round() 方法可把一个数字舍入为最接近的整数
        return Math.round(p * 100);
    }

    public static List<StockCwzb> getCwzb(String content, String symbol) throws Exception {
        Document document = Jsoup.parse(content);
        Element element = document.getElementById("BalanceSheetNewTable0");

        if (element == null) {
            return null;
        }
        Elements trs = element.getElementsByTag("tr");
        //FileUtil.writeAsString(new File("D:/test.txt"), element.html());

        //如果没有数据就返回null
        if (trs == null || trs.get(1) == null || trs.get(1).getElementsByTag("td").size() == 0) {
            return null;
        }

        List<StockCwzb> list = new ArrayList<>();

        //private Date date;              // 报告日期
        parseCwzb(list, trs.get(1).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setDate", Date.class));

        //private String code;            // 股票代码
        for (StockCwzb cwzb : list) {
            cwzb.setSymbol(symbol);
        }

        //private Float jgzb_tbmgsy;      // 摊薄每股收益(元)
        parseCwzb(list, trs.get(3).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_tbmgsy", Float.class));

        //private Float jgzb_jqmgsy;      // 加权每股收益(元)
        parseCwzb(list, trs.get(4).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_jqmgsy", Float.class));

        //private Float jgzb_mgsy;        // 每股收益_调整后(元)
        parseCwzb(list, trs.get(5).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mgsy", Float.class));

        //private Float jgzb_kfmgsy;      // 扣除非经常性损益后的每股收益(元)
        parseCwzb(list, trs.get(6).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_kfmgsy", Float.class));

        //private Float jgzb_mgjzc_b;     // 每股净资产_调整前(元)
        parseCwzb(list, trs.get(7).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mgjzc_b", Float.class));

        //private Float jgzb_mgjzc_a;     // 每股净资产_调整后(元)
        parseCwzb(list, trs.get(8).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mgjzc_a", Float.class));

        //private Float jgzb_mgxjl;       // 每股经营性现金流(元)
        parseCwzb(list, trs.get(9).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mgxjl", Float.class));

        //private Float jgzb_mggjj;       // 每股资本公积金(元)
        parseCwzb(list, trs.get(10).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mggjj", Float.class));

        //private Float jgzb_mgwfplr;     // 每股未分配利润(元)
        parseCwzb(list, trs.get(11).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setJgzb_mgwfplr", Float.class));

        //private Float ylnl_zzclrl;      // 总资产利润率(%)
        parseCwzb(list, trs.get(14).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_zzclrl", Float.class));

        //private Float ylnl_zzcjlrl;     // 总资产净利润率(%)
        parseCwzb(list, trs.get(16).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_zzcjlrl", Float.class));

        //private Float ylnl_cbfylrl;     // 成本费用利润率(%)
        parseCwzb(list, trs.get(17).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_cbfylrl", Float.class));

        //private Float ylnl_gbbcl;       // 股本报酬率(%)
        parseCwzb(list, trs.get(21).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_gbbcl", Float.class));

        //private Float ylnl_jzcbcl;      // 净资产报酬率(%)
        parseCwzb(list, trs.get(22).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_jzcbcl", Float.class));

        //private Float ylnl_zcbcl;       // 资产报酬率(%)
        parseCwzb(list, trs.get(23).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_zcbcl", Float.class));

        //private Float ylnl_xsmll;       // 销售毛利率(%)
        parseCwzb(list, trs.get(24).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_xsmll", Float.class));

        //private Float ylnl_fzybz;       // 非主营比重
        parseCwzb(list, trs.get(26).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_fzybz", Float.class));

        //private Float ylnl_jzcsyl;      // 净资产收益率(%)
        parseCwzb(list, trs.get(31).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_jzcsyl", Float.class));

        //private Float ylnl_jqjzcsyl;    // 加权净资产收益率(%)
        parseCwzb(list, trs.get(32).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_jqjzcsyl", Float.class));

        //private Long ylnl_kfhjlr;       // 扣除非经常性损益后的净利润(元)
        parseCwzb(list, trs.get(33).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setYlnl_kfhjlr", Long.class));

        //private Float cznl_zyywzzl;     // 主营业务收入增长率(%)
        parseCwzb(list, trs.get(35).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setCznl_zyywzzl", Float.class));

        //private Float cznl_jlrzzl;      // 净利润增长率(%)
        parseCwzb(list, trs.get(36).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setCznl_jlrzzl", Float.class));

        //private Float cznl_jzczzl;      // 净资产增长率(%)
        parseCwzb(list, trs.get(37).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setCznl_jzczzl", Float.class));

        //private Float cznl_zzczzl;      // 总资产增长率(%)
        parseCwzb(list, trs.get(38).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setCznl_zzczzl", Float.class));

        //private Float zbjg_gdqybl;      // 股东权益比率(%)
        parseCwzb(list, trs.get(56).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setZbjg_gdqybl", Float.class));

        //private Float zbjg_zbgdhbl;     // 资本固定化比率(%)
        parseCwzb(list, trs.get(63).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setZbjg_zbgdhbl", Float.class));

        //private Float zbjg_cqbl;        // 产权比率(%)
        parseCwzb(list, trs.get(64).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setZbjg_cqbl", Float.class));

        //private Float zbjg_zcfzl;       // 资产负债率(%)
        parseCwzb(list, trs.get(67).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setZbjg_zcfzl", Float.class));

        //private Long zbjg_zzc;          // 总资产(元)
        parseCwzb(list, trs.get(68).getElementsByTag("td"), StockCwzb.class.getMethod(
                "setZbjg_zzc", Long.class));

        return list;
    }

    //解析页面内容,封装到对象中,一页是一年的数据
    private static void parseCwzb(List<StockCwzb> list, Elements tds, Method method) throws Exception {
        if (tds.size() == 0) {
            return;
        }

        //如果list没有值,则添加财务指标
        if (list.size() == 0) {
            for (int i = 0; i < tds.size() - 1; i++) {
                list.add(new StockCwzb());
            }
        }

        for (int i = 1; i < tds.size(); i++) {
            //如果没有值,就继续遍历
            if ("--".equals(tds.get(i).text())) {
                continue;
            }

            //获取方法额参数
            Class clazz = method.getParameterTypes()[0];

            //判断参数的类型并设置数据
            if (String.class == clazz) {
                method.invoke(list.get(i - 1), tds.get(i).text());
            } else if (Date.class == clazz) {
                method.invoke(list.get(i - 1), sdf.parse(tds.get(i).text()));
            } else if (Float.class == clazz) {
                method.invoke(list.get(i - 1), Float.parseFloat(tds.get(i).text()));
            } else if (Long.class == clazz) {
                String str = tds.get(i).text();
                if (str.contains(".")) {
                    method.invoke(list.get(i - 1), Long.parseLong(str.substring(0, str.indexOf("."))));
                } else {
                    method.invoke(list.get(i - 1), Long.parseLong(str));
                }
            }
        }
    }


}
